﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using HtmlAgilityPack;

// ReSharper disable CheckNamespace
namespace Yah.Parser
// ReSharper restore CheckNamespace
{
	public static class HtmlParser
	{
		public static HtmlDocument GetHtmlDoc(string url, out string redirectedUrl, out string content)
		{
			var buffer = GetDownloadBuffer(url, out redirectedUrl);
			var doc = new HtmlDocument();
			content = Encoding.UTF8.GetString(buffer);
			doc.LoadHtml(content);
			return doc;
		}

		public static HtmlDocument GetHtmlDoc(byte[] buffer)
		{
			try
			{
				var doc = new HtmlDocument();
				doc.LoadHtml(Encoding.UTF8.GetString(buffer));
				return doc;
			}
			catch
			{
				return null;
			}
		}

		public static HashSet<string> FetchImgFromHtml(string link, HtmlDocument doc, out string ogImg)
		{
			ogImg = GetOgImage(doc);
			var imgs = doc.DocumentNode.SelectNodes("//img");
			if (String.IsNullOrEmpty(ogImg) && (imgs == null || imgs.Count == 0))
				return null;
			var images = new HashSet<string>();
			if (!String.IsNullOrEmpty(ogImg))
			{
				images.Add(ogImg);
			}
			var url = new Uri(link);
			foreach (var node in imgs)
			{
				ValidateImgNode(images, url, node.Attributes["src"]);
				ValidateImgNode(images, url, node.Attributes["data-src"]);
			}
			return images;
		}

		private static void ValidateImgNode(ICollection<string> images, Uri url, HtmlAttribute attribute)
		{
			if (attribute == null) 
				return;
			var s = attribute.Value.Replace("\n", "");
			if (String.IsNullOrEmpty(s) || s.ToLower().Contains("captcha"))
				return;
			s = HttpUtility.HtmlDecode(s);
			var src = new Uri(url, s);
			if (!String.IsNullOrEmpty(src.AbsoluteUri) && !images.Contains(src.AbsoluteUri))
			{
				images.Add(src.AbsoluteUri);
			}
		}

		public static byte[] GetDownloadBuffer(string link, out string redirectedUrl)
		{
			var req = (HttpWebRequest) WebRequest.Create(link);
			req.Headers[HttpRequestHeader.AcceptEncoding] = "gzip, deflate";
			req.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
			req.Method = "GET";
			req.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4";
			var response = req.GetResponse();
			redirectedUrl = response.ResponseUri.AbsoluteUri;
			var stream = response.GetResponseStream();
			return ReadStream(stream);
		}

		private static byte[] ReadStream(Stream input)
		{
			var buffer = new byte[16*1024];
			using (var ms = new MemoryStream())
			{
				int read;
				while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
				{
					ms.Write(buffer, 0, read);
				}
				return ms.ToArray();
			}
		}

		public static string GetTitle(HtmlDocument doc)
		{
			string title;
			var node = doc.DocumentNode.SelectSingleNode("//meta[@name ='title' or @name = 'Title']//text()");
			if (node != null)
			{
				title = node.InnerText;
			}
			else
			{
				node = doc.DocumentNode.SelectSingleNode("//title/text()");
				title = node != null ? node.InnerText : "";
			}
			return HttpUtility.HtmlDecode(title).Trim();
		}

		public static string GetDesc(HtmlDocument doc)
		{
			string description;
			var node = doc.DocumentNode.SelectSingleNode("//meta[@name ='description' or @name = 'Description']");
			if (node != null)
			{
				description = node.GetAttributeValue("content", "");
			}
			else
			{
				node = doc.DocumentNode.SelectSingleNode("//p/text()[string-length() > 120]");
				description = node != null ? node.InnerText : "";
			}
			return HttpUtility.HtmlDecode(description).Trim();
		}

		public static string GetOgImage(HtmlDocument doc)
		{
			string img = null;
			var node = doc.DocumentNode.SelectSingleNode("//meta[@property='og:image']");
			if (node != null)
				img = node.GetAttributeValue("content", null);
			if (img == null)
			{
				node = doc.DocumentNode.SelectSingleNode("//link[@rel='image_src']");
				if (node != null)
					img = node.GetAttributeValue("href", null);
			}
			img = HttpUtility.HtmlDecode(img);
			return img;
		}

		static readonly Regex HtmlRegex = new Regex("[^'\"<>()]+?\\.(jpg|jpeg|gif|png)", RegexOptions.Compiled);

		public static void RegExFetchImg(HashSet<string> imgs, string link, byte[] buffer)
		{
			var content = Encoding.UTF8.GetString(buffer);
			RegExFetchImg(imgs, link, content);
		}

		public static void RegExFetchImg(HashSet<string> imgs, string link, string content)
		{
			var url = new Uri(link);
			var matches = HtmlRegex.Matches(content);
			foreach (Match item in matches)
			{
				try
				{
				    var s = item.Value.Replace("\n", "").Trim();
				    if (String.IsNullOrEmpty(s) || s.ToLower().Contains("captcha"))
				        continue;
				    s = HttpUtility.HtmlDecode(s);
				    var src = new Uri(url, s);
				    if (!String.IsNullOrEmpty(src.AbsoluteUri) && !imgs.Contains(src.AbsoluteUri))
				    {
				        imgs.Add(src.AbsoluteUri);
				    }
				}
				catch (Exception)
				{
                    throw new Exception(@"RegExFetchImg");
				}
			}
		}
	}
}